﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace Gauss.Isp
{
    public class KillProcess
    {
        // [StructLayout(LayoutKind.Sequential)]
        private struct PROCESS_BASIC_INFORMATION
        {
            public int ExitStatus;
            public int PebBaseAddress;
            public int AffinityMask;
            public int BasePriority;
            public uint UniqueProcessId;
            public uint InheritedFromUniqueProcessId;

        }

        [DllImport("kernel32.dll")]
        static extern bool TerminateProcess(uint hProcess, int exitCode);

        [DllImport("ntdll.dll")]
        static extern int NtQueryInformationProcess(
           IntPtr hProcess,
           int processInformationClass /* 0 */,
           ref PROCESS_BASIC_INFORMATION processBasicInformation,
           uint processInformationLength,
           out uint returnLength
        );

        /// <summary>
        /// Terminate a process tree
        /// </summary>
        /// <param name="hProcess">The handle of the process</param>
        /// <param name="processID">The ID of the process</param>
        /// <param name="exitCode">The exit code of the process</param>
        public static void TerminateProcessTree(IntPtr hProcess, uint processID, int exitCode)
        {
            // Retrieve all processes on the system
            Process[] processes = Process.GetProcesses();
            foreach (Process p in processes)
            {
                // Get some basic information about the process
                PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
                try
                {
                    uint bytesWritten;
                    NtQueryInformationProcess(
                       p.Handle,
                       0,
                       ref pbi,
                       (uint)Marshal.SizeOf(pbi), out bytesWritten); // == 0 is OK

                    // Is it a child process of the process we're trying to terminate?
                    if (pbi.InheritedFromUniqueProcessId == processID)
                        // Terminate the child process (and its child processes)
                        // by calling this method recursively
                        TerminateProcessTree(p.Handle, pbi.UniqueProcessId, exitCode);
                }
                catch (Exception /* ex */)
                {
                    // Ignore, most likely 'Access Denied'
                }
            }

            // Finally, terminate the process itself:
            TerminateProcess((uint)hProcess, exitCode);
        }
    }
}
